package indi.cloud.common.service.impl;


import indi.cloud.common.config.ExcelWidthStyleStrategy;
import indi.cloud.common.service.CommonDownLoadService;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.fastjson.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static indi.cloud.common.utils.DataUtils.strToNumber;
import static indi.cloud.common.utils.DataUtils.unitChange;

/**
 * @author yangyifan
 * @version 1.0
 * @date 2023/4/4 11:57
 * @Description
 */
@Service
public class CommonDownLoadServiceImpl<T> implements CommonDownLoadService<T> {

    private static final Logger logger = LoggerFactory.getLogger(CommonDownLoadServiceImpl.class);

    /**
     * 下载excel
     *
     * @param response
     * @param fileName   文件名称
     * @param data       返回的数据集，用来生成excel
     * @param excelModel excel模板
     */
    @Override
    public void export(HttpServletResponse response, String fileName, List data, Class excelModel) {
        try {
            String newFileName = new String(fileName.getBytes(StandardCharsets.UTF_8));

            response.setContentType("application/vnd.ms-excel;charset=utf-8");
            response.setCharacterEncoding("utf8");
            response.setHeader("Content-disposition", "attachment;filename=" + URLEncoder.encode(newFileName,"UTF-8") + ".xlsx");
            ExcelWriter excelWriter;
            excelWriter = EasyExcel.write(response.getOutputStream()).head(excelModel)
                    .build();
            WriteSheet writeSheet = EasyExcel.writerSheet(0, newFileName).registerWriteHandler(new ExcelWidthStyleStrategy()).build();
            List tempData = JSONObject.parseArray(JSONObject.toJSONString(data), excelModel);
            excelWriter.write(tempData, writeSheet);
            excelWriter.finish();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    /**
     * @param response
     * @param fileName   文件名称
     * @param data       返回的数据集，用来生成excel
     * @param columnName 自定义列,List<Map>     name、field
     */
    @Override
    public void export(HttpServletResponse response, String fileName, List data, List columnName) {
        //根据自己的业务逻辑生成对应的List<Object>类型的集合
        List<Object> list = new ArrayList<>();
        try {
            response.setContentType("application/vnd.ms-excel;charset=utf-8");
            response.setCharacterEncoding("utf-8");
            response.setHeader("Content-disposition", "attachment;filename=" + URLEncoder.encode(fileName,"UTF-8") + ".xlsx");
            //控制 导出字段 未控制顺序
            EasyExcel.write(response.getOutputStream())
                    .head(head(columnName))
                    .registerWriteHandler(new ExcelWidthStyleStrategy())
                    .includeColumnFiledNames(data)
                    .sheet(fileName)
                    .doWrite(dataList(data, columnName));
        } catch (IOException e) {
            logger.error("导出异常", e);
        }
    }

    private List<List<String>> head(List<JSONObject> columnName) {
        List<List<String>> list = new ArrayList<>();
        for (int i = 0; i < columnName.size(); i++) {
            List<String> head = new ArrayList<>();
            String column_name = columnName.get(i).getString("name");
            String column_head = unitChange(column_name);
            String field = columnName.get(i).getString("field");
            head.add(column_head);
            list.add(head);
        }
        return list;
    }

    /**
     * 设置表格信息
     *
     * @param dataList 查询出的数据
     * @param fileList 需要显示的字段
     * @return
     */
    private static List<List<Object>> dataList(List<Object> dataList, List<JSONObject> fileList) {
        List<List<Object>> list = new ArrayList<>();
        for (Object person : dataList) {
            List<Object> data = new ArrayList<>();
            fileList.stream().forEach(x -> {
                data.add(getFieldValue(x.getString("field"), person));
            });
            list.add(data);
        }
        return list;
    }

    /**
     * 根据传入的字段获取对应的get方法，如name,对应的getName方法
     *
     * @param fieldName 字段名
     * @param person    对象
     * @return
     */
    private static Object getFieldValue(String fieldName, Object person) {
        try {
            if (person instanceof JSONObject || person instanceof HashMap) {
                Object o = ((Map) person).get(fieldName);
                if (o == null) {
                    return null;
                }
                if (o instanceof BigDecimal) {
                    return ((BigDecimal) o).toPlainString();
                }
                if (o instanceof Float) {
                    return strToNumber(o);
                }
                return o.toString();
            }
            return null;
        } catch (Exception e) {
            return null;
        }
    }

    @Override
    public void exportManySheet(HttpServletResponse response, String fileName, List<List<Object>> data, List<List<JSONObject>> columnName, List<String> sheetName) {
        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding("utf-8");
        // 这里URLEncoder.encode可以防止中文乱码
        try {
            response.setHeader("Content-disposition", "attachment;filename=" + URLEncoder.encode(fileName,"UTF-8") + ".xlsx");
            //新建ExcelWriter
            ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream())
                    .registerWriteHandler(new ExcelWidthStyleStrategy()).build();
            for (int i = 0; i < columnName.size(); i++) {
                WriteSheet mainSheet = EasyExcel.writerSheet(i, sheetName.get(i)).head(head(columnName.get(i))).build();
                //向sheet0写入数据 传入空list这样只导出表头
                List<Object> objects = data.get(i);
                List<JSONObject> column = columnName.get(i);
                List<List<Object>> lists = dataList(objects, column);
                excelWriter.write(lists, mainSheet);
            }
            //关闭流
            excelWriter.finish();
        } catch (IOException e) {
            logger.error("导出异常{}", e.getMessage());
        }
    }
}
